#ifndef _OPENLOG_H_
#define _OPENLOG_H_

#ifdef __cplusplus
#define _FUNC_ __PRETTY_FUNCTION__
#else
#define _FUNC_ __FUNCTION__
#endif // __cplusplus

#ifdef __cplusplus

extern "C"
{
#endif // __cplusplus

#include <stdio.h>
#include <time.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>

    extern pthread_mutex_t _log_mutex;

#define TMP_STRING_SIZE 1024

#define LOG(level, ...)                                                                                                                                                                                \
    do                                                                                                                                                                                                 \
    {                                                                                                                                                                                                  \
        char _tmpCString[TMP_STRING_SIZE] = {0};                                                                                                                                                       \
                                                                                                                                                                                                       \
        struct timespec ts;                                                                                                                                                                            \
        clock_gettime(CLOCK_REALTIME, &ts);                                                                                                                                                            \
                                                                                                                                                                                                       \
        struct tm *tm_info;                                                                                                                                                                            \
        tm_info = localtime(&ts.tv_sec);                                                                                                                                                               \
                                                                                                                                                                                                       \
        char time_str[26];                                                                                                                                                                             \
        strftime(time_str, 26, "%Y-%m-%d %H:%M:%S", tm_info);                                                                                                                                          \
                                                                                                                                                                                                       \
        const char *_FILENAME = strrchr(__FILE__, '\\');                                                                                                                                               \
        if (_FILENAME != NULL)                                                                                                                                                                         \
            _FILENAME++;                                                                                                                                                                               \
        else                                                                                                                                                                                           \
            _FILENAME = __FILE__;                                                                                                                                                                      \
                                                                                                                                                                                                       \
        pthread_t _tid = pthread_self();                                                                                                                                                               \
        int _res = snprintf(_tmpCString, TMP_STRING_SIZE - 1, "%s.%03ld %s [%s:%d] [tid=%04lu] <%s> ", time_str, ts.tv_nsec / 1000000, level, _FILENAME, __LINE__, (unsigned long)_tid, __FUNCTION__); \
        snprintf(_tmpCString + _res, (TMP_STRING_SIZE - 1) - _res, __VA_ARGS__);                                                                                                                       \
        pthread_mutex_lock(&_log_mutex);                                                                                                                                                               \
        printf("%s\n", _tmpCString);                                                                                                                                                                   \
        pthread_mutex_unlock(&_log_mutex);                                                                                                                                                             \
    } while (0)

#define LOGA(...) LOG("FAIL", __VA_ARGS__)
#define LOGE(...) LOG("ERROR", __VA_ARGS__)
#define LOGW(...) LOG("WARN", __VA_ARGS__)
#define LOGI(...) LOG("INFO", __VA_ARGS__)
#define LOGD(...) LOG("DEBUG", __VA_ARGS__)
#define LOGV(...) LOG("VERBOSE", __VA_ARGS__)

    inline void openLog_init()
    {
        pthread_mutex_init(&_log_mutex, NULL);
    }

    inline void openLog_destroy()
    {
        pthread_mutex_destroy(&_log_mutex);
    }

#ifdef __cplusplus
}
#endif // __cplusplus

#endif // _OPENLOG_H_